const fs = require('fs')
const path = require('path')
const promisify = require('util').promisify
const Handlebars = require('handlebars')
const stat = promisify(fs.stat)
const readdir = promisify(fs.readdir)
const {compressFile} = require('../config/defaultConfig')
const tplPath = path.join(__dirname,'../template/dir.tpl')
const {getContentTypes} = require('./mime')
const compress = require('./compress')
const range = require('./range')
const isFresh = require('./cache')

const source = fs.readFileSync(tplPath)
const template = Handlebars.compile(source.toString())

module.exports = async function(req,res,filePath,config){
    try{
        const stats = await stat(filePath)
        if(stats.isFile()) {
            res.setHeader('Content-Type',getContentTypes(filePath))

            if (isFresh(stats, req, res)) {
                res.statusCode = 304
                res.end()
                return 
            }

            let rs
            const {code,start,end} = range(stats.size,req,res)
            if (code === 200) {
                res.statusCode = 200
                rs = fs.createReadStream(filePath)
            } else {
                // 206：部分内容
                res.statusCode = 206
                // 读取文件片段
                rs = fs.createReadStream(filePath, {start, end})
            }
            if(filePath.match(compressFile)) {
                rs = compress(rs,req,res)
            }
            rs.pipe(res)
        } else if (stats.isDirectory()){
            const files = await readdir(filePath)
            res.statusCode=200
            res.setHeader('Content-Type','text/html')
            // path.relative相对路径
            const dir = path.relative(config.root,filePath)
            const data = {
                title: path.basename(filePath),
                dir: dir ? `/${dir}` : '',
                files
            }
            res.end(template(data))
        }
    }catch(err){
        res.statusCode = 404
        res.setHeader('Content-Type','text/plain')
        res.end(`${filePath} is not a directory or file`)
        return
    }
}